// HTMLParser Library $Name: v1_6 $ - A java-based parser for HTML
// http://sourceforge.org/projects/htmlparser
// Copyright (C) 2003 Derrick Oswald
//
// Revision Control Information
//
// $Source: /cvsroot/htmlparser/htmlparser/src/org/htmlparser/lexerapplications/thumbelina/TileSet.java,v $
// $Author: derrickoswald $
// $Date: 2004/07/31 16:42:30 $
// $Revision: 1.2 $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

package org.htmlparser.lexerapplications.thumbelina;

import java.awt.Rectangle;
import java.util.Enumeration;
import java.util.Vector;

/**
 * Class to track picture regions.
 */
public class TileSet
/*
 * extends java.awt.Canvas implements java.awt.event.ActionListener,
 * java.awt.event.MouseListener, java.awt.event.WindowListener
 */
{
	/**
	 * The list of Pictures.
	 */
	protected Vector mRegions;

	/**
	 * Construct a tile set.
	 */
	public TileSet() {
		mRegions = new Vector();
	}

	/**
	 * Get the number of tiles in this collection.
	 * 
	 * @return The number of pictures showing. Note that the same image and URL
	 *         may be showing (different pieces) in several locations.
	 */
	public int getSize() {
		return (mRegions.size());
	}

	/**
	 * Get the list of pictures.
	 * 
	 * @return An enumeration over the picture objects in this set.
	 */
	public Enumeration getPictures() {
		return (mRegions.elements());
	}

	/**
	 * Add a single picture to the list.
	 * 
	 * @param r
	 *            The picture to add.
	 */
	public void add(final Picture r) {
		Vector regions; // this will be the new set
		Enumeration e;
		Picture rover;
		Rectangle intersection;
		Vector splits;
		Enumeration frags;

		regions = new Vector();
		for (e = getPictures(); e.hasMoreElements();) {
			rover = (Picture) e.nextElement();
			if (rover.intersects(r)) {
				intersection = rover.intersection(r);
				if (!intersection.equals(rover)) {
					// incoming lies completely within the existing picture
					// or touches the existing picture somehow
					splits = split(r, rover, false);
					for (frags = splits.elements(); frags.hasMoreElements();)
						regions.addElement(frags.nextElement());
				} else
					// incoming covers existing... drop the existing picture
					// but be sure to release the image memory
					rover.setImage(null);
			} else
				// no conflict, keep the existing
				regions.addElement(rover);
		}
		regions.addElement(r);
		mRegions = regions;
	}

	/**
	 * Split the large picture. Strategy: split horizontally (full width strips
	 * top and bottom). NOTE: top and bottom make sense only in terms of AWT
	 * coordinates.
	 * 
	 * @param small
	 *            The incoming picture.
	 * @param large
	 *            The encompassing picture. The attributes of this one are
	 *            propagated to the fragments.
	 * @param keep
	 *            If <code>true</code>, the center area is kept, otherwise
	 *            discarded.
	 * @return The fragments from the large picture.
	 */
	private Vector split(final Picture small, final Picture large,
			final boolean keep) {
		Picture m;
		Vector ret;

		ret = new Vector();

		if (large.intersects(small)) {
			Rectangle intersection = large.intersection(small);

			// if tops don't match split off the top
			if ((intersection.y + intersection.height) != (large.y + large.height)) {
				m = new Picture(large);
				m.y = (intersection.y + intersection.height);
				m.height = (large.y + large.height) - m.y;
				ret.addElement(m);
			}

			// if left sides don't match make a left fragment
			if (intersection.x != large.x) {
				m = new Picture(large);
				m.y = intersection.y;
				m.width = intersection.x - large.x;
				m.height = intersection.height;
				ret.addElement(m);
			}

			// the center bit
			if (keep) {
				m = new Picture(large);
				m.x = intersection.x;
				m.y = intersection.y;
				m.width = intersection.width;
				m.height = intersection.height;
				ret.addElement(m);
			}

			// if right sides don't match make a right fragment
			if ((intersection.x + intersection.width) != (large.x + large.width)) {
				m = new Picture(large);
				m.x = intersection.x + intersection.width;
				m.y = intersection.y;
				m.width = (large.x + large.width) - m.x;
				m.height = intersection.height;
				ret.addElement(m);
			}

			// if bottoms don't match split off the bottom
			if (intersection.y != large.y) {
				m = new Picture(large);
				m.height = (intersection.y - large.y);
				ret.addElement(m);
			}
		}

		return (ret);
	}

	/**
	 * Find the Picture at position x,y
	 * 
	 * @param x
	 *            The x coordinate of the point to examine.
	 * @param y
	 *            The y coordinate of the point to examine.
	 * @return The picture at that point, or <code>null</code> if there are
	 *         none.
	 */
	public Picture pictureAt(final int x, final int y) {
		Picture m;
		Picture ret;

		ret = null;

		for (int i = 0; (null == ret) && (i < mRegions.size()); i++) {
			m = (Picture) mRegions.elementAt(i);
			if (m.contains(x, y))
				ret = m;
		}

		return (ret);
	}

	/**
	 * Move the given picture to the top of the Z order.
	 * 
	 * @param picture
	 *            The picture to add.
	 */
	public void bringToTop(final Picture picture) {
		Picture m;
		Picture ret;

		ret = null;

		for (int i = 0; (null == ret) && (i < mRegions.size());) {
			m = (Picture) mRegions.elementAt(i);
			if (picture.same(m))
				mRegions.removeElementAt(i);
			else
				i++;
		}
		add(picture);

	}

	// //
	// // Unit test.
	// //
	//
	// // and need to add:
	// extends
	// java.awt.Canvas
	// implements
	// java.awt.event.ActionListener,
	// java.awt.event.MouseListener,
	// java.awt.event.WindowListener
	// // to the class definition
	//
	// boolean mVerbose;
	// int mCounter;
	// java.awt.Point origin;
	// Rectangle last;
	// int type;
	//
	// static java.awt.MenuBar menuMain;
	// static java.awt.Menu Options;
	// static java.awt.MenuItem repeat;
	// static java.awt.MenuItem clear;
	// static java.awt.TextField status;
	//
	// // checks if adding the rectangle causes an overlap
	// boolean checkAdd (Rectangle r, Vector v)
	// {
	// Enumeration e;
	// boolean ret;
	// ret = false;
	//
	// for (e = v.elements (); !ret && e.hasMoreElements (); )
	// ret = r.intersects ((Rectangle)e.nextElement ());
	//
	// return (ret);
	// }
	//
	// void paintwait ()
	// {
	// java.awt.Graphics g = getGraphics ();
	// if (null != g)
	// paint (g);
	// Thread.yield ();
	// try
	// {
	// Thread.sleep (1000);
	// }
	// catch (Exception exception)
	// {
	// }
	// }
	//
	// void add ()
	// {
	// if (null != last)
	// {
	// Picture m = new Picture (last);
	// try
	// {
	// m.setURL (new URL ("http://localhost/image#" + mCounter++));
	// }
	// catch (java.net.MalformedURLException murle)
	// {
	// murle.printStackTrace ();
	// }
	// this.add (m);
	// repaint ();
	// }
	// }
	//
	// //
	// // WindowListener interface
	// //
	// public void windowOpened (java.awt.event.WindowEvent e) {}
	// public void windowClosing (java.awt.event.WindowEvent e)
	// {
	// System.exit (0);
	// }
	// public void windowClosed (java.awt.event.WindowEvent e) {}
	// public void windowIconified (java.awt.event.WindowEvent e) {}
	// public void windowDeiconified (java.awt.event.WindowEvent e) {}
	// public void windowActivated (java.awt.event.WindowEvent e) {}
	// public void windowDeactivated (java.awt.event.WindowEvent e) {}
	//
	// //
	// // ActionListener interface
	// //
	// public void actionPerformed (java.awt.event.ActionEvent event)
	// {
	// Object object = event.getSource();
	// if (object == repeat)
	// add ();
	// else if (object == clear)
	// {
	// mRegions = new Vector ();
	// repaint ();
	// }
	// }
	//
	// //
	// // MouseListener Interface
	// //
	//
	// public void mouseClicked (java.awt.event.MouseEvent event)
	// {
	// if (mVerbose)
	// System.out.println ("DrawTarget.mouseClicked " + event);
	// }
	//
	// public void mouseReleased (java.awt.event.MouseEvent event)
	// {
	// if (mVerbose)
	// System.out.println ("DrawTarget.mouseReleased " + event);
	// if (null != origin)
	// {
	// last = new Rectangle (
	// Math.min (origin.x, event.getX ()),
	// Math.min (origin.y, event.getY ()),
	// Math.abs (event.getX () - origin.x),
	// Math.abs (event.getY () - origin.y));
	// add ();
	// origin = null;
	// }
	// }
	//
	// public void mouseEntered (java.awt.event.MouseEvent event)
	// {
	// if (mVerbose)
	// System.out.println ("DrawTarget.mouseEntered " + event);
	// }
	//
	// public void mouseExited (java.awt.event.MouseEvent event)
	// {
	// if (mVerbose)
	// System.out.println ("DrawTarget.mouseExited " + event);
	// }
	//
	// public void mousePressed (java.awt.event.MouseEvent event)
	// {
	// if (mVerbose)
	// System.out.println ("DrawTarget.mousePressed " + event);
	// if (event.isMetaDown ())
	// {
	// status.setText (getDetails (event.getX (), event.getY ()));
	// }
	// else
	// origin = new java.awt.Point (event.getX (), event.getY ());
	// }
	//
	// public void update (java.awt.Graphics graphics)
	// {
	// paint (graphics);
	// }
	//
	// static final java.awt.Color[] mColours =
	// {
	// java.awt.Color.blue,
	// java.awt.Color.cyan,
	// java.awt.Color.gray,
	// java.awt.Color.green,
	// java.awt.Color.orange,
	// java.awt.Color.pink,
	// java.awt.Color.red,
	// java.awt.Color.yellow,
	// java.awt.Color.lightGray,
	// java.awt.Color.darkGray,
	// };
	//
	// public void paint (java.awt.Graphics graphics)
	// {
	// java.awt.Dimension size = getSize ();
	// graphics.setColor (getBackground ());
	// graphics.fillRect (0, 0, size.width + 1, size.height + 1);
	//
	// if (0 == mRegions.size ())
	// {
	// graphics.setColor (getForeground ());
	// graphics.drawString (
	// "Click and drag to create a picture.", 10, 20);
	// graphics.drawString (
	// "Right click a picture for details.", 10, 40);
	// }
	// else
	// {
	// Enumeration e = getPictures ();
	// while (e.hasMoreElements ())
	// {
	// Picture m = (Picture)e.nextElement ();
	// String url = m.getURL ().toExternalForm ();
	// int n = url.indexOf ('#');
	// n = Integer.parseInt (url.substring (n + 1))
	// java.awt.Color colour = mColours[n % mColours.length];
	// graphics.setColor (colour);
	// graphics.fillRect (m.x, m.y, m.width + 1, m.height + 1);
	// graphics.setColor (java.awt.Color.black);
	// graphics.drawRect (m.x, m.y, m.width, m.height);
	// }
	// checkOverlap (graphics);
	// }
	// }
	//
	// void checkOverlap (java.awt.Graphics graphics)
	// {
	// Picture m;
	// Picture _m;
	// Rectangle r;
	//
	// graphics.setColor (java.awt.Color.magenta);
	// for (int i = 0; i < mRegions.size (); i++)
	// {
	// m = (Picture)mRegions.elementAt (i);
	// for (int j = i + 1; j < mRegions.size (); j++)
	// {
	// _m = (Picture)mRegions.elementAt (j);
	// if (m.intersects (_m))
	// {
	// r = m.intersection (_m);
	// System.out.println (
	// "overlap ("
	// + r.x
	// + ","
	// + r.y
	// + ") ("
	// + (r.x + r.width)
	// + ","
	// + (r.y + r.height)
	// + ")");
	// graphics.fillRect (r.x, r.y, r.width + 1, r.height + 1);
	// }
	// }
	// }
	// }
	//
	// String getDetails (int x, int y)
	// {
	// Picture m;
	// String ret;
	//
	// ret = null;
	//
	// // find the Picture
	// for (int i = 0; (null == ret) && (i < mRegions.size ()); i++)
	// {
	// m = (Picture)mRegions.elementAt (i);
	// if (m.contains (x, y))
	// ret = m.toString ();
	// }
	// if (null == ret)
	// ret = "";
	//
	// return (ret);
	// }
	//
	// public static void main (String[] args)
	// {
	// java.awt.Frame frame;
	//
	// frame = new java.awt.Frame ();
	// frame.setSize (400,400);
	// menuMain = new java.awt.MenuBar();
	// Options = new java.awt.Menu ("Options");
	// repeat = new java.awt.MenuItem("Repeat");
	// Options.add (repeat);
	// clear = new java.awt.MenuItem("Clear");
	// Options.add (clear);
	//
	// menuMain.add (Options);
	// frame.setMenuBar (menuMain);
	//
	// java.awt.Insets insets = frame.getInsets ();
	//
	// TileSet buffy = new TileSet ();
	// buffy.setLocation (insets.left + 10, insets.top + 10);
	// buffy.setBackground (java.awt.Color.lightGray.brighter ());
	// buffy.setVisible (true);
	//
	// frame.add (buffy, "Center");
	// status = new java.awt.TextField ();
	// frame.add (status, "South");
	//
	// frame.addWindowListener (buffy);
	// buffy.addMouseListener (buffy);
	// repeat.addActionListener (buffy);
	// clear.addActionListener (buffy);
	//
	// frame.setVisible (true);
	//
	// }
}

/*
 * Revision Control Modification History
 * 
 * $Log: TileSet.java,v $ Revision 1.2 2004/07/31 16:42:30 derrickoswald Remove
 * unused variables and other fixes exposed by turning on compiler warnings.
 * 
 * Revision 1.1 2003/09/21 18:20:56 derrickoswald Thumbelina Created a lexer GUI
 * application to extract images behind thumbnails. Added a task in the ant
 * build script - thumbelina - to create the jar file. You need JDK 1.4.x to
 * build it. It can be run on JDK 1.3.x in crippled mode. Usage: java -Xmx256M
 * thumbelina.jar [URL]
 * 
 * 
 */
